﻿// owner 蒋家伟

#include "SerialPortWorker.h"

// qt
#include <QTime>

// jsdk
#include "StringUtils.h"
#include "Dbg_Warn_Define.h"

using namespace jsdk;

OwnerPtr<SerialPortWorker> jsdk::SerialPortWorker::create(ISerialPortEventHandler * pSerialPortEventHandler)
{
    OwnerPtr<SerialPortWorker> opSerialPortWorker = NEW_AS_OWNERPTR(SerialPortWorker);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opSerialPortWorker, L"串口worker创建失败", L"蒋家伟", L"2023-07-27");
    opSerialPortWorker->m_wpSerialPortHandler = pSerialPortEventHandler;
    return std::move(opSerialPortWorker);
}

void jsdk::SerialPortWorker::SerialPortDeleter::operator()(QSerialPort* pSerialPort)
{
    if (pSerialPort)
    {
        pSerialPort->deleteLater();
    }
}

bool jsdk::SerialPortWorker::isOnLine() const
{
    return m_opSerialPort != nullptr;
}

void jsdk::SerialPortWorker::onReadyRead()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSerialPort, L"串口对象还没有创建", L"蒋家伟", L"2023-08-15");
    if (m_wpSerialPortHandler)
    {
        m_wpSerialPortHandler->recvMessage(m_opSerialPort->readAll());
    }
    return;
}

void jsdk::SerialPortWorker::onSend(QByteArray msg, qint64 length)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSerialPort, L"串口对象还没有创建", L"蒋家伟", L"2023-08-15");

    qint64 sendedbyte = 0;
    QTime startTime;
    startTime.start();
    const char* pStream = msg.constData();
    while (sendedbyte < length && startTime.elapsed() < 2000)
    {
        sendedbyte += m_opSerialPort->write(pStream + sendedbyte, length - sendedbyte);
    }

    if (m_wpSerialPortHandler)
    {
        m_wpSerialPortHandler->sendMessageFeedback(sendedbyte == length);
    }
}

void jsdk::SerialPortWorker::onConnect(
    QString port,
    int baudRate,
    short dataBits,
    short stopBits,
    short parity,
    short flowControl)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(!m_opSerialPort, L"当前串口已经链接，请勿多次触发", L"蒋家伟", L"2023-07-26");

    m_opSerialPort.swap(NEW_AS_OWNERPTR_WITH_DELETER(QSerialPort, SerialPortDeleter));
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSerialPort, L"串口创建失败，目标端口名称:" + port.toStdWString() , L"蒋家伟", L"2023-07-26");

    // 信号与槽连接
    bool success = init();
    DBG_WARN_AND_RETURN_VOID_UNLESS(success, L"Work的信号与槽连接失败", L"蒋家伟", L"2023-07-26");

    m_opSerialPort->setPortName(port);
    QSerialPort::BaudRate a = static_cast<QSerialPort::BaudRate>(baudRate);
    m_opSerialPort->setBaudRate(a);
    QSerialPort::DataBits b = static_cast<QSerialPort::DataBits>(dataBits);
    m_opSerialPort->setDataBits(b);
    QSerialPort::StopBits c = static_cast<QSerialPort::StopBits>(stopBits);
    m_opSerialPort->setStopBits(c);
    QSerialPort::Parity d = static_cast<QSerialPort::Parity>(parity);
    m_opSerialPort->setParity(static_cast<QSerialPort::Parity>(d));

    QSerialPort::FlowControl e = static_cast<QSerialPort::FlowControl>(flowControl);
    m_opSerialPort->setFlowControl(e);

    if (!m_opSerialPort->open(QIODevice::ReadWrite))
    {
        m_opSerialPort.reset();
        if (m_wpSerialPortHandler)
        {
            m_wpSerialPortHandler->connected(false);
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(false, L"串口对象打开失败，其串口名称为 : " + port.toStdWString(), L"蒋家伟", L"2023-08-15");
        return;
    }
    if (m_wpSerialPortHandler)
    {
        m_wpSerialPortHandler->connected(true);
    }
    return;
}

void jsdk::SerialPortWorker::onError(QSerialPort::SerialPortError serialPortError) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSerialPort, L"串口还没有创建", L"蒋家伟", L"2023-07-26");
    if (m_wpSerialPortHandler)
    {
        m_wpSerialPortHandler->serialPortError(serialPortError);
    }
}

bool jsdk::SerialPortWorker::init() const
{
    // 信号与槽连接
    bool success = connect(m_opSerialPort.get(), &QSerialPort::readyRead, this, &jsdk::SerialPortWorker::onReadyRead);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"串口等待读取的信号与槽连接失败", L"蒋家伟", L"2023-07-26");

    success = connect(m_opSerialPort.get(), SIGNAL(errorOccurred(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"串口错误信号与槽连接失败", L"蒋家伟", L"2023-07-26");
    return success;
}